﻿// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using ILLink.Shared.TypeSystemProxy;
using Mono.Cecil;
using Mono.Cecil.Cil;

namespace Mono.Linker
{
    public static class ParameterHelpers
    {
        public static ParameterIndex GetParameterIndex(MethodDefinition thisMethod, Instruction operation)
        {
            // Thank you Cecil, Operand being a ParameterDefinition instead of an integer,
            // (except for Ldarg_0 - Ldarg_3, where it's null) makes all of this really convenient...
            // NOT.
            Code code = operation.OpCode.Code;
            return code switch
            {
                Code.Ldarg_0
                or Code.Ldarg_1
                or Code.Ldarg_2
                or Code.Ldarg_3
                => GetLdargParamIndex(),

                Code.Starg
                or Code.Ldarg
                or Code.Starg_S
                or Code.Ldarg_S
                or Code.Ldarga
                or Code.Ldarga_S
                => GetParamSequence(),

                _ => throw new ArgumentException($"{nameof(GetParameterIndex)} expected an ldarg or starg instruction, got {operation.OpCode.Name}")
            };

            ParameterIndex GetLdargParamIndex()
            {
                return (ParameterIndex)(code - Code.Ldarg_0);
            }
            ParameterIndex GetParamSequence()
            {
                ParameterDefinition param = (ParameterDefinition)operation.Operand;
                return (ParameterIndex)param.Sequence;
            }
        }
    }
}
